#ifndef NET_TIMER_WHEEL_H
#define NET_TIMER_WHEEL_H

#include <functional>
#include <vector>
#include <unordered_map>
#include <memory>
#include <string>

#include "logger.h"

namespace net {

/**
 * @brief 任务回调函数类型
 * 
 * 定义定时器触发时执行的回调函数签名
 */
using TaskFunc = std::function<void()>;

/**
 * @brief 资源释放回调函数类型
 * 
 * 定义用于清理定时器内部资源的回调函数签名
 */
using ReleaseFunc = std::function<void()>;

class EventLoop;
class Channel;

/**
 * @brief 定时器任务基类，封装定时执行的回调函数
 * 
 * 每个TimerTask对象代表一个定时任务，包含任务ID、延迟时间和回调函数。
 * 任务会在超时后执行，或被取消（Cancel）。
 */
class TimerTask
{
public:
    /**
     * @brief 构造函数
     * @param id 任务唯一标识
     * @param delay 延迟时间（秒）
     * @param cb 任务回调函数
     */
    TimerTask(uint64_t id, uint32_t delay, const TaskFunc &cb);

    /**
     * @brief 析构函数
     * 
     * 如果任务未被取消，则执行回调函数，并调用释放函数清理资源
     */
    ~TimerTask();

    /**
     * @brief 取消任务
     * 
     * 设置任务为已取消状态，析构时不再执行回调
     */
    void cancel()   { _canceled = true; }

    /**
     * @brief 设置资源释放回调
     * @param cb 释放资源的回调函数
     */
    void setRelease(const ReleaseFunc &cb) { _release = cb; }

    /**
     * @brief 获取任务延迟时间
     * @return 延迟时间（秒）
     */
    uint32_t delayTime() const { return _timeout; }

private:
    uint64_t _id;         // 定时器任务对象id 与 connFd 关联
    uint32_t _timeout;    // 定时任务的超时时间
    bool _canceled;       // false-表示没有被取消，true-表示被取消
    TaskFunc _task_cb;    // 定时器要执行的定时任务
    ReleaseFunc _release; // 用于删除TimerWheel中保存的定时器对象信息
};

/**
 * @brief 时间轮定时器实现
 * 
 * 使用时间轮算法管理大量定时任务，每秒转动一格，执行到期任务。
 * 时间轮容量为60秒，适合管理短延迟任务。
 */
class TimerWheel
{
public:
    /**
     * @brief 构造函数
     * @param loop 所属事件循环
     *
     * 所有定时任务的回调会被强制在loop所在线程执行，保证了任务执行环境的线程安全性。
     */
    TimerWheel(EventLoop *loop);

    /**
     * @brief 析构函数
     * 
     * 清理定时器资源
     */
    ~TimerWheel();

    /**
     * @brief 添加定时任务
     * @param id 任务唯一标识
     * @param delay 延迟时间（秒），必须小于时间轮容量
     * @param cb 任务回调函数
     */
    void timerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb);

    /**
     * @brief 刷新/延迟定时任务
     * @param id 任务唯一标识
     * 
     * 将任务重新加入时间轮，延迟时间保持不变
     */
    void timerRefresh(uint64_t id);

    /**
     * @brief 取消定时任务
     * @param id 任务唯一标识
     */
    void timerCancel(uint64_t id);

    /**
     * @brief 检查任务是否存在
     * @param id 任务唯一标识
     * @return 是否存在
     */
    bool hasTimer(uint64_t id) const;

private:
    using WeakTask = std::weak_ptr<TimerTask>;  // 弱引用，不影响对象生命周期
    using PtrTask = std::shared_ptr<TimerTask>; // 强引用，管理对象生命周期

    int _tick;      // 当前时间轮的的秒针，走到哪里，哪里就释放执行
    int _capacity;  // 时间轮的容量 -- 最大延迟时间，默认60秒
    std::vector<std::vector<PtrTask>> _wheel;       // 时间轮槽位，每个槽位存储多个任务
    std::unordered_map<uint64_t, WeakTask> _timers; // 任务ID到任务的映射，快速查找

    EventLoop *_loop;   // 所属事件循环
    int _timerfd;       // Linux定时器文件描述符
    std::unique_ptr<Channel> _timerChannel; // 定时器的Channel对象，用于监听定时事件

    /**
     * @brief 从哈希表中移除任务
     * @param id 任务唯一标识
     */
    void removeTimer(uint64_t id);

    /**
     * @brief 创建定时器文件描述符
     * @return 定时器文件描述符
     * 
     * 使用timerfd_create创建每秒触发一次的定时器
     */
    static int createTimerfd();

    /**
     * @brief 读取定时器事件
     * @return 超时次数
     * 
     * 读取timerfd中的值，获取从上次读取后发生的超时次数
     */
    int readTimefd();

    /**
     * @brief 执行当前槽位的所有任务
     * 
     * 清空当前槽位的任务列表，触发任务对象的析构，执行回调
     */
    void runTimerTask();

    /**
     * @brief 定时器事件回调函数
     * 
     * 处理定时器触发事件，读取超时次数并执行对应次数的任务检查
     */
    void onTime();

    /**
     * @brief 在事件循环线程中添加任务
     * @param id 任务唯一标识
     * @param delay 延迟时间（秒）
     * @param cb 任务回调函数
     * 
     * 内部方法，确保在EventLoop线程中执行任务添加操作
     */
    void timerAddInLoop(uint64_t id, uint32_t delay, const TaskFunc &cb);

    /**
     * @brief 在事件循环线程中刷新任务
     * @param id 任务唯一标识
     * 
     * 内部方法，确保在EventLoop线程中执行任务刷新操作
     */
    void timerRefreshInLoop(uint64_t id);

    /**
     * @brief 在事件循环线程中取消任务
     * @param id 任务唯一标识
     * 
     * 内部方法，确保在EventLoop线程中执行任务取消操作
     */
    void timerCancelInLoop(uint64_t id);
};

} // namespace net

#endif // NET_TIMER_WHEEL_H